package com.lechi.web.service.impl;


import com.alibaba.fastjson2.JSON;
import com.lechi.iot.netty.utils.BytesToHexUtil;
import com.lechi.iot.netty.utils.ModbusCrc16Utils;
import com.lechi.web.constants.Constants;
import com.lechi.web.dto.IotDeviceCmdCreateDto;
import com.lechi.web.service.IIotGenCmdAndCacheAndScheduleService;
import com.lechi.web.system.domain.IotDeviceCmdBo;
import com.lechi.web.system.domain.IotDeviceCmdParse;
import com.lechi.web.system.mapper.iot.IotDeviceCmdMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * The type Iot gen cmd and cache and schedule service.
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IotGenCmdAndCacheAndScheduleServiceImpl implements IIotGenCmdAndCacheAndScheduleService {

    private final IotDeviceCmdMapper iotDeviceCmdMapper;

    @Transactional(rollbackFor = {RuntimeException.class, Exception.class})
    public void genCmdAndUpdateCmd(Long deviceId) {
        List<IotDeviceCmdParse> iotDeviceCmdCreates = iotDeviceCmdMapper.selectIotDeviceCmdListForCreate(deviceId);
        List<IotDeviceCmdParse> iotDeviceCmdCreateList = iotDeviceCmdMapper.selectIotDeviceCmdListByOrder(deviceId);
        for (IotDeviceCmdParse iotDeviceCmdCreate : iotDeviceCmdCreates) {
            IotDeviceCmdCreateDto iotDeviceCmdCreateDto = new IotDeviceCmdCreateDto();
            BeanUtils.copyProperties(iotDeviceCmdCreate, iotDeviceCmdCreateDto);
            for (IotDeviceCmdParse iotDeviceCmdBo : iotDeviceCmdCreateList) {
                if (iotDeviceCmdCreate.getStationAddr().equals(iotDeviceCmdBo.getStationAddr())) {
                    if (iotDeviceCmdCreateDto.getMinOffsetCode() > iotDeviceCmdBo.getOffsetCode()) {
                        iotDeviceCmdCreateDto.setMinOffsetCode(iotDeviceCmdBo.getOffsetCode());
                    }
                    if (iotDeviceCmdCreateDto.getMaxOffsetCode() < iotDeviceCmdBo.getOffsetCode()) {
                        iotDeviceCmdCreateDto.setMaxOffsetCode(iotDeviceCmdBo.getOffsetCode());
                    }
                }
            }
            AtomicReference<Integer> registerNum = new AtomicReference<>(0);
            iotDeviceCmdCreateList.forEach(iotDeviceCmd -> {
                if (iotDeviceCmd.getStationAddr().equals(iotDeviceCmdCreateDto.getStationAddr())) {
                    String beginBit = iotDeviceCmdCreateDto.getMinOffsetCode() - 1 < 16 ? "000" + Integer.toHexString(iotDeviceCmdCreateDto.getMinOffsetCode() - 1) : "00" + Integer.toHexString(iotDeviceCmdCreateDto.getMinOffsetCode() - 1);
                    if (Constants.FLOAT_FORMAT_32.equals(iotDeviceCmd.getDataFormat()) || Constants.INTEGER_DATA_FORMAT_32.equals(iotDeviceCmd.getDataFormat())) {
                        registerNum.set((iotDeviceCmdCreateDto.getMaxOffsetCode() - iotDeviceCmdCreateDto.getMinOffsetCode()) + 2);
                    } else if (Constants.FLOAT_FORMAT_16.equals(iotDeviceCmd.getDataFormat()) || Constants.INTEGER_DATA_FORMAT_16.equals(iotDeviceCmd.getDataFormat())) {
                        registerNum.set((iotDeviceCmdCreateDto.getMaxOffsetCode() - iotDeviceCmdCreateDto.getMinOffsetCode()) + 1);
                    }
                    String register = registerNum.get() < 16 ? "000" + Integer.toHexString(registerNum.get()) : "00" + Integer.toHexString(registerNum.get());
                    String cmd = iotDeviceCmdCreateDto.getStationAddr() + iotDeviceCmd.getFunctionCode() + beginBit + register;
                    byte[] arr = BytesToHexUtil.hexStrToBinaryStr(cmd);
                    if (arr == null) {
                        log.error("生成的指令为空,规则内容: {}, 原始指令数据：{}", JSON.toJSON(iotDeviceCmdCreateDto), JSON.toJSON(iotDeviceCmd));
                        return;
                    }
                    IotDeviceCmdBo iotDeviceCmdBo = new IotDeviceCmdBo();
                    iotDeviceCmdBo.setId(iotDeviceCmd.getId());
                    iotDeviceCmdBo.setCmd(cmd + ModbusCrc16Utils.getCrcString(arr));
                    iotDeviceCmdMapper.updateIotDeviceCmd(iotDeviceCmdBo);
                }
            });
        }
    }
}
